(function () {
	var fs = require('fs');
	var path = require('path');

	var request = require('request');
	var extract = require('extract-zip');
	var recursiveCopy = require('recursive-copy');

	var spawn = require('child_process').spawn;

	var platform = process.platform;
	platform = /^win/.test(platform) ? 'win' : /^darwin/.test(platform) ? 'mac' : 'linux' + (process.arch == 'ia32' ? '32' : '64');

	function Updater(options) {
		this.status = '';
		this.progress = '0%';

		this.options = {
			downloadFileName: 'app_new.zip',
			basePath: options.basePath,
			downloadPath: options.basePath,
			unpackPath: path.join(options.basePath, 'app_new'),
			copyFromPath: path.join(options.basePath, 'app_new'),
			copyToPath: path.join(options.basePath, 'app'),
			runAppPath: options.runAppPath
		};

		this.setStatus = function (_status) {
			this.status = _status;
		};

		this.setProgress = function (_progress) {
			this.progress = _progress;
		};
	};

    /**
     * check new version
     */
	Updater.prototype.isNewVersionExists = function (url, currentVersion) {
		return new Promise(function () {
			http.get(url, function (res) {
				res.on('data', function (chunk) {
					console.log('data -> chunk:', chunk);
				})

				res.on('close', function () {
					console.log('data -> close');
					resolve();
				});
			})
		}, function () {
			reject();
		});
	}


    /**
     * todo:
     * remove files of last update
     */
	Updater.prototype.removeLastFiles = function () {
		var self = this;

		// remove app_new.zip
		var downloadedFilePath = path.join(self.options.downloadPath, self.options.downloadFileName);
		var unpackDirPath = self.options.unpackPath;

		var stats = fs.statSync(downloadedFilePath);
		if (stats.isFile()) {
			fs.unlinkSync(downloadedFilePath);
		}

		function delDir(dirPath) {
			var files = fs.readdirSync(dirPath);
			var stats;
			var filePath;

			files.forEach(function (file, index) {
				filePath = path.resolve(dirPath, file);
				stats = fs.statSync(filePath);

				if (stats.isDirectory()) {
					delDir(filePath);
				} else if (stats.isFile()) {
					fs.unlinkSync(filePath);
				} else {
					// 
				}
			});

			fs.rmdirSync(dirPath);
		}

		// remove app_new
		stats = fs.statSync(unpackDirPath);
		if (stats.isDirectory()) {
			delDir(unpackDirPath);
		} else {
			fs.unlinkSync(unpackDirPath);
		}

		return true;
	};

    /**
     * download new version zip file
     */
	Updater.prototype.download = function (url) {
		var self = this;
		self.status = 'download';
		var downloadPath = path.join(self.options.downloadPath, self.options.downloadFileName);

		console.info('download file \"', downloadPath, '\"');
		return new Promise(function (resolve, reject) {
			var contentType = '';
			var fws;

			try {
				fws = fs.createWriteStream(downloadPath);
				request.get(url)
					.on('response', function (res) {
						self.progress = '100%';
						contentType = res.headers['content-type'];
					})
					.on('error', function (err) {
						fws.close();
						fws = null;
						reject(err);
					})
					.pipe(fws)
					.on('error', function (err) {
						fws.close();
						fws = null;
						reject(err);
					})
					.on('close', function () {
						if (contentType.indexOf('application/zip') > -1) {
							resolve();
						} else {
							reject({ fileType: contentType });
						}
					});
			} catch (e) {
				reject('download file error:' + downloadPath);
				return;
			}
		});
	}

    /**
     * unpack downloaded zip file
     */
	Updater.prototype.unpack = function (fileName) {
		var self = this;

		console.info('unpack file \"', path.join(self.options.downloadPath, self.options.downloadFileName), '\"');
		return new Promise(function (resolve, reject) {
			extract(path.join(self.options.downloadPath, self.options.downloadFileName),
				{ dir: self.options.unpackPath },
				function (err) {
					if (err) {
						reject(err);
					} else {
						resolve();
					}
				}
			)
		});
	};

    /**
     * check download file
     */
	Updater.prototype.checkDownloadedFile = function () {
		var self = this;

		console.info('check file before replace');
		return new Promise(function (resolve, reject) {
			var unpackPath = self.options.unpackPath;

			/* check if the constant.js exists*/
			fs.stat(path.resolve(unpackPath, 'scripts/constants/constant.js'), function (err, data) {
				if (err) {
					console.log(err);
					reject(err);
				} else {
					resolve();
				}
			});
		});
	};

    /**
     * copy unpacked new version directory to app
     */
	Updater.prototype.copyDir = function () {
		var self = this;

		console.info('copy file from \"', self.options.copyFromPath, '\"', 'to \"', self.options.copyToPath, '\"');
		return new Promise(function (resolve, reject) {
			recursiveCopy(self.options.copyFromPath, self.options.copyToPath, { overwrite: true },
				function (err, results) {
					if (err) {
						reject(err);
					} else {
						resolve();
					}
				});
		});
	}

	var pRun = {
        /**
         * @private
         */
		mac: function (appPath, args, options) {
			//spawn
			if (args && args.length) {
				args = [appPath].concat('--args', args);
			} else {
				args = [appPath];
			}
			return run('open', args, options);
		},
        /**
         * @private
         */
		win: function (appPath, args, options, cb) {
			return run(appPath, args, options, cb);
		},
        /**
         * @private
         */
		linux32: function (appPath, args, options, cb) {
			var appExec = path.join(appPath, path.basename(this.getAppExec()));
			fs.chmodSync(appExec, 0755)
			if (!options) options = {};
			options.cwd = appPath;
			return run(appPath + "/" + path.basename(this.getAppExec()), args, options, cb);
		}
	};

	pRun.linux64 = pRun.linux32;

    /**
     * @private
     */
	function run(path, args, options) {
		var opts = {
			detached: true
		};
		for (var key in options) {
			opts[key] = options[key];
		}
		var sp = spawn(path, args, opts);
		sp.unref();
		// return sp;
	}

	Updater.prototype.restart = function (cb) {
		var self = this;

		// return pRun[platform].apply(this, self.options.runAppPath);
		// run(self.options.runAppPath);
		// var sp = spawn(self.options.runAppPath, [self.options.basePath, self.options.runAppPath], {});
		// sp.unref();
		cb();
	};

	// module.exports = Updater;
	window.Updater = Updater;
})();

(function () {
	'use strict';

	function Progress(options) {
		this.progress = 0;

		this.options = {
			isMax: false,
			progressMax: 95
		}

		if (options && options.progressMax) {
			this.options.progressMax = options.progressMax;
		}
	};

	Progress.prototype.init = function () {
		var self = this;
		self.progress = 0;
	};

	Progress.prototype.increase = function () {
		var self = this;

		var progress = parseInt(self.progress);

		if (progress < self.options.progressMax) {
			progress += Math.floor(Math.random() * 5);
		} else {
			self.options.isMax = true;
		}

		self.progress = progress;

		return {
			isMax: self.options.isMax,
			progress: progress + '%'
		};
	};

	window.Progress = Progress;
})();